Skip to content

fix(auth): preserve follow-scoped GitHub tokens during OAuth login#373

Open
Ridanshi wants to merge 3 commits into
Dev-Card:mainfrom
Ridanshi:fix/github-token-scope-preservation
Open

fix(auth): preserve follow-scoped GitHub tokens during OAuth login#373
Ridanshi wants to merge 3 commits into
Dev-Card:mainfrom
Ridanshi:fix/github-token-scope-preservation

Conversation

@Ridanshi
Copy link
Copy Markdown
Contributor

Closes #355

Summary

Fixes a cross-flow GitHub OAuth token lifecycle issue where normal GitHub login could silently overwrite an existing follow-capable GitHub integration token with a reduced-scope login token.

Previously:

  • the GitHub connect/follow flow stored tokens with follow-capable scopes such as user:follow
  • a later GitHub login flow performed an unconditional oAuthToken.upsert
  • the lower-scope login token overwrote the existing integration token
  • GitHub follow functionality silently broke afterward

This PR preserves higher-privilege follow-capable tokens during subsequent GitHub login flows while keeping the existing login behavior intact.


Root Cause

connect.ts stores GitHub integration tokens in oAuthToken with follow-capable scopes.

Later, auth.ts performed an unconditional:

oAuthToken.upsert(...)

using the GitHub login token (read:user user:email).

Because both flows shared the same persisted GitHub credential record:

  • the existing integration token was overwritten
  • user:follow capability was lost
  • follow automation silently failed afterward

The issue was difficult to detect because:

  • login flow worked independently
  • connect flow worked independently
  • follow flow worked independently with valid scopes
  • but cross-flow token persistence invariants were not preserved

Fix Strategy

Before replacing an existing GitHub token during login, the backend now:

  1. checks existing stored GitHub scopes
  2. detects whether the existing token contains user:follow
  3. compares incoming login token scopes
  4. preserves the existing higher-privilege token when the new token has reduced scopes

Behavior after fix:

  • existing follow-capable tokens are preserved
  • normal GitHub login still succeeds
  • JWT issuance/login flow remains unchanged
  • legitimate token upgrades are still allowed
  • new users without stored tokens still persist normally

Files Changed

  • apps/backend/src/routes/auth.ts
  • apps/backend/src/__tests__/auth.github-token.test.ts

Tests

Added focused regression coverage for:

  • preserving an existing follow-capable token
  • subsequent reduced-scope GitHub login
  • normal login flow still succeeding
  • legitimate token upgrades
  • preserving follow integration state consistency

Verification

..\..\node_modules\.bin\vitest.CMD run src\__tests__\auth.github-token.test.ts src\__tests__\connect.test.ts src\__tests__\follow.test.ts

Result:

Test Files  3 passed (3)
Tests       6 passed (6)

Notes

This PR intentionally keeps scope minimal and focused on GitHub OAuth token scope preservation.

No OAuth architecture rewrite, schema redesign, provider refactor, or unrelated auth cleanup was introduced.

Ridanshi added 2 commits May 28, 2026 21:28
…v-Card#300)

Public events remain fully accessible without authentication.
Private events now require the caller to be the organizer or a
confirmed attendee; unauthenticated callers receive 401 and
authenticated non-members receive 403.

Changes:
- add getRequestUserId() soft-auth helper (returns null gracefully,
  never throws, used only on read endpoints)
- add canAccessEvent() returns 'allowed' | 'unauthenticated' |
  'forbidden' so callers can issue semantically correct 401 vs 403
- GET /api/events/:slug — visibility enforced after DB fetch;
  isPublic field intentionally excluded from response body
- GET /api/events/:slug/attendees — visibility enforced before
  returning any attendee data
- Routes registered with /api/events prefix in app.ts (removes the
  double-prefix issue from the prior implementation)
- 46 tests added covering public access, private 401/403, organizer
  access, attendee access, no-sensitive-field leakage, and unchanged
  pagination/sorting behaviour
Avoid replacing an existing user:follow OAuth token with a lower-scope GitHub login token.

Closes Dev-Card#355
@Ridanshi Ridanshi force-pushed the fix/github-token-scope-preservation branch from 23ec502 to 1b9130c Compare May 28, 2026 16:09
…import

Register @fastify/cookie in test buildApp so request.cookies is populated.
Mock the encryption module directly instead of via app.decorate so the
encrypt() call in auth.ts resolves correctly. Pass oauth_state cookie in
inject headers and fix the redirect assertion to use a URL fragment (#)
consistent with how auth.ts builds the mobile redirect URI.
@Ridanshi Ridanshi force-pushed the fix/github-token-scope-preservation branch from 1b9130c to 7520db3 Compare May 28, 2026 16:17
@Harxhit Harxhit added the gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. label May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GitHub OAuth login silently overwrites follow-scoped token and breaks GitHub follow integration

2 participants